﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Jacobi.Vst.Core;
using Jacobi.Vst.Interop.Host;
using System.Diagnostics;

namespace KinectedMusic.Audio
{

    class VSTPlugin
    {
        // context for vst plugin
        private VstPluginContext instrument;
        private VstAudioBuffer[] outputBuffers;
        private VstAudioBuffer[] inputBuffers;
        private VstAudioBufferManager inputMgr;
        private VstAudioBufferManager outputMgr;
        private string pluginURL;
        int blockSize;

        //TODO: let it load from any folder?
        public VSTPlugin(string pluginName, int blockSize)
        {
            pluginURL = "./" + pluginName + ".dll";
            this.blockSize = blockSize;
        }

        public void OutputParameters()
        {
            instrument.PluginCommandStub.SetParameter(8, 1.0f);
            instrument.PluginCommandStub.SetParameter(80, 0.1f);
            for (int i = 0; i < instrument.PluginInfo.ParameterCount; i++)
            {
                string name = instrument.PluginCommandStub.GetParameterName(i);
                string label = instrument.PluginCommandStub.GetParameterLabel(i);
                string display = instrument.PluginCommandStub.GetParameterDisplay(i);
                Console.Write(i + "  ");
                float para = instrument.PluginCommandStub.GetParameter(i);
                Console.Write(name, display, label, String.Empty);
                Console.WriteLine(para);
            }


        }


        public void LoadVST()
        {
            instrument = OpenPlugin(pluginURL);

            Console.WriteLine("Plugin loaded: " + instrument.PluginCommandStub.GetVendorString());

            StartVST();

            int inputCount = instrument.PluginInfo.AudioInputCount;
            int outputCount = instrument.PluginInfo.AudioOutputCount;

            inputMgr = new VstAudioBufferManager(inputCount, blockSize);
            outputMgr = new VstAudioBufferManager(outputCount, blockSize);

            // Initialise to 0, array is already 0
            foreach (VstAudioBuffer buffer in inputMgr.ToArray())
            {
                for (int i = 0; i < blockSize; i++)
                {
                    buffer[i] = 0;
                }
            }

            instrument.PluginCommandStub.SetBlockSize(blockSize);
            instrument.PluginCommandStub.SetSampleRate(44100f);

            inputBuffers = inputMgr.ToArray();
            outputBuffers = outputMgr.ToArray();

            //??test
            OutputParameters();

            //????maybe i can add later for debug or help to set up XML
            //Editor editor = new Editor();
            //editor.PluginCommandStub = instrument.PluginCommandStub;
            //Thread thread = new Thread(new ThreadStart(editor.Start));
            //thread.Start();
        }

        public void StartVST()
        {
            instrument.PluginCommandStub.StartProcess();
            instrument.PluginCommandStub.MainsChanged(true);
        }

        public void StopVST()
        {
            instrument.PluginCommandStub.StopProcess();
            instrument.PluginCommandStub.MainsChanged(false);
        }

        public VstAudioBuffer[] GetOutputBuffers(VstAudioBuffer[] inputBuffers)
        {
            instrument.PluginCommandStub.ProcessReplacing(inputBuffers, outputBuffers);
            return outputBuffers;
        }

        public VstAudioBuffer[] GetOutputBuffers()
        {
            instrument.PluginCommandStub.ProcessReplacing(inputBuffers, outputBuffers);
            return outputBuffers;

        }

        public void SendMIDI(VstEvent[] eventMidi)
        {
            instrument.PluginCommandStub.ProcessEvents(eventMidi);
        }
       

        private VstPluginContext OpenPlugin(string pluginPath)
        {
            try
            {
                HostCommandStub hostCmdStub = new HostCommandStub();
                hostCmdStub.PluginCalled += new EventHandler<PluginCalledEventArgs>(HostCmdStubPluginCalled);

                VstPluginContext ctx = VstPluginContext.Create(pluginPath, hostCmdStub);

                // add custom data to the context
                ctx.Set("PluginPath", pluginPath);
                ctx.Set("HostCmdStub", hostCmdStub);

                // actually open the plugin itself
                ctx.PluginCommandStub.Open();

                return ctx;
            }
            catch (Exception e)
            {
                Console.WriteLine("Loading plugin has failed: " + e.ToString());
            }

            return null;
        }

        private void HostCmdStubPluginCalled(object sender, PluginCalledEventArgs e)
        {
            HostCommandStub hostCmdStub = (HostCommandStub)sender;

            // can be null when called from inside the plugin main entry point.
            if (hostCmdStub.PluginContext.PluginInfo != null)
            {
                Debug.WriteLine("Plugin " + hostCmdStub.PluginContext.PluginInfo.PluginID + " called:" + e.Message);
            }
            else
            {
                Debug.WriteLine("The loading Plugin called:" + e.Message);
            }
        }


    }
}
